package com.picket.controller;

import java.beans.PropertyEditorSupport;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Required;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.google.appengine.api.users.User;
import com.picket.Messages;
import com.picket.ResourceNotFoundException;
import com.picket.domain.EmailEnvelope;
import com.picket.domain.Event;
import com.picket.domain.GaeUser;
import com.picket.domain.Match;
import com.picket.domain.MatchWithPredictions;
import com.picket.domain.Pool;
import com.picket.domain.UserPool;
import com.picket.domain.UserPrediction;
import com.picket.form.EmailForm;
import com.picket.form.PoolForm;
import com.picket.service.EmailerService;
import com.picket.service.IEventService;
import com.picket.service.IGaeUserService;
import com.picket.service.IMatchService;
import com.picket.service.IPoolService;
import com.picket.service.IUserPoolService;
import com.picket.service.IUserPredictionService;

@Controller
//@RequestMapping(value = "/pool")
public class PoolController extends BaseController {
	private IPoolService poolService;
	private IUserPoolService userPoolService;
	private IEventService eventService;
	private EmailerService emailService;
    private IGaeUserService gaeUserService;
	private IMatchService matchService;
	private IUserPredictionService userPredService;
	
	@Required
	public void setMatchService(IMatchService matchService) {
		this.matchService = matchService;
	}

	@Required
	public void setUserPredictionService(IUserPredictionService userPredService) {
		this.userPredService = userPredService;
	}
 	@Required
	public void setGaeUserService(IGaeUserService gaeUserService){
		this.gaeUserService = gaeUserService;
	}

	@Required
	public void setPoolService(IPoolService poolService) {
		this.poolService = poolService;
	}

	@Required
	public void setEventService(IEventService eventService) {
		this.eventService = eventService;
	}

	@Required
	public void setUserPoolService(IUserPoolService userPoolService) {
		this.userPoolService = userPoolService;
	}

	@RequestMapping(value = "/pool/create", method = RequestMethod.GET)
	public String doCreateView(Model model) {
		final User user = userService.getCurrentUser();
		final PoolForm poolForm = new PoolForm();
		model.addAttribute("poolForm", poolForm);
		model.addAttribute("allEvents", eventService.getAllEvents());

		return "/pool/create";
	}

	@RequestMapping(value = "/pool/join", method = RequestMethod.GET)
	public String doJoinView(Model model) {
		return "/pool/join";
	}

	@RequestMapping(value = "/admin/pool/all", method = RequestMethod.GET)
	public String doPoolView(Model model) {
		Collection<Pool> pools = poolService.getAllPools();
		model.addAttribute("allPools", pools);
		return "/pool/viewall";
	}

	@RequestMapping(value = "/pool/join/user", method = RequestMethod.GET)
	public String doJoinUser(String referral) {
		long userPoolId;
		if (referral == null || referral.trim().length() == 0) {
			return "/pool/join";
		}
		Pool pool = poolService.findByReferral(referral);

		if (pool == null) {
			return "/pool/join";
		}
		String userEmail = userService.getCurrentUser().getEmail();
		Collection<UserPool> userPools = userPoolService.findByEmailAndPoolId(userEmail,pool.getId());
		// check if userpool already exists for the user
		if (userPools.size() == 0) {
			poolService.createAllPoolRelatedInfo(pool);
			userPools =  userPoolService.findByEmailAndPoolId(userEmail,pool.getId());
			userPoolId = ((UserPool)(userPools.toArray())[0]).getId();
		} else {
			UserPool upool = (UserPool)(userPools.toArray())[0];
			userPoolId = upool.getId();
		}
		return "redirect:/users/predictions/" + userPoolId;
	}

	@RequestMapping(value = "/pool/create", method = RequestMethod.POST)
	public String createPool(@Valid PoolForm poolForm, BindingResult result) {
		if (result.hasErrors()) {
			// model.addAttribute("poolForm",poolForm);
			return "/pool/create";
		}
		Pool pool = new Pool();
		pool.setName(poolForm.getName());
		pool.setType("Private");
		pool.setEventId(poolForm.getEvent().getId());
		Authentication authentication = SecurityContextHolder.getContext()
				.getAuthentication();
		GaeUser currentUser = (GaeUser) authentication.getPrincipal();
		pool.setOwner(currentUser.getEmail());
		Pool created = poolService.create(pool);
		long poolId = created.getId();
		poolService.createAllPoolRelatedInfo(created);
		return "redirect:invite?id=" + poolId;
	}

	/*
	 * @RequestMapping(value="/invite",method=RequestMethod.GET) public String
	 * doInvite(BindingResult result) { return "redirect:invite/" ; }
	 */
/*	@RequestMapping(value = "/pool/join", method = RequestMethod.POST)
	public String joinPool(@Valid Pool pool, BindingResult result) {
		if (result.hasErrors()) {
			return "pool/join";
		}
		return "redirect:pool/" + (poolService.createAllPoolRelatedInfo(pool));
	}
*/
	@RequestMapping(value = "/pool/invite{id}", method = RequestMethod.GET)
	public String doInvite(Long id, Model model, HttpServletRequest request) {
		Authentication authentication = SecurityContextHolder.getContext()
				.getAuthentication();
		GaeUser currentUser = (GaeUser) authentication.getPrincipal();
		Pool pool = poolService.getPool(id);
		Event event = eventService.getEvent(pool.getEventId());

		EmailEnvelope envelope = new EmailEnvelope();
		envelope.setFromAddress("picket.2011@gmail.com");
		envelope.setToAddress(currentUser.getEmail());
		envelope.setSubject("Pool Created Successfully.");
		envelope.setMessageBody(Messages.poolCreationConfirmation(currentUser,
				pool, event,request));
		emailService.sendEmail(envelope);

		EmailForm emailForm = new EmailForm();
		emailForm.setFromAddress("picket.2011@gmail.com");
		emailForm.setSubject("Invitation to join prediction pool");
		emailForm.setMessageBody(Messages.inviteFriendsToJoinPool(currentUser,
				pool, event,request));
		model.addAttribute("pool", pool);
		model.addAttribute("event", event);
		model.addAttribute("emailForm", emailForm);
		return "/pool/invite";
	}

	@RequestMapping(value = "/pool/invite", method = RequestMethod.POST)
	public String sendInvitationToPool(@Valid EmailForm emailForm,
			BindingResult result, Long id) {
		if (result.hasErrors()) {
			// model.addAttribute("emailForm",emailForm);
			return "redirect:/pool/invite";
		}
		EmailEnvelope envelope = new EmailEnvelope();
		envelope.setFromAddress(emailForm.getFromAddress());
		envelope.setToAddress(emailForm.getToAddress());
		envelope.setSubject(emailForm.getSubject());
		envelope.setMessageBody(emailForm.getMessageBody());
		emailService.sendEmail(envelope);
		UserPool upool = userPoolService.findByPoolId(id);
		return "redirect:/users/predictions/" + upool.getId();
	}

	@RequestMapping(value = "/admin/pool/{id}", method = RequestMethod.GET)
	public String getView(@PathVariable Long id, Model model) {
		Collection<Pool> pools = poolService.getAllPools();
		if (pools == null) {
			throw new ResourceNotFoundException(id);
		}
		Pool pool = poolService.getPool(id);
		model.addAttribute("pool", pool);
		return "/pool/view";
	}

	@InitBinder
	public void initBinder(WebDataBinder binder) throws Exception {

		binder.registerCustomEditor(Event.class, "event",
				new PropertyEditorSupport() {
					@Override
					public void setAsText(String text) {
						Event event = eventService.getEvent(Long
								.parseLong(text));
						setValue(event);
					}
				});
	}

/*	@RequestMapping(value = "all", method = RequestMethod.GET)
	public String getView(Model model) {
		Collection<Pool> pools = poolService.getAllPools();

		model.addAttribute("pools", pools);
		return "/pool/view";
	}
*/
	public EmailerService getEmailService() {
		return emailService;
	}

	public void setEmailService(EmailerService emailService) {
		this.emailService = emailService;
	}

	@RequestMapping(value = "/pool/users/{id}", method = RequestMethod.GET)
	public String getPoolUserView(@PathVariable Long id, Model model) {
		UserPool userPool = userPoolService.getUserPool(id);
		Collection<UserPool> usersInPool = userPoolService
				.getAllUserPoolInfoForPool(userPool.getPoolId());
		model.addAttribute("usersInPool", usersInPool);
		model.addAttribute("userPoolId",id);
		return "/pool/poolUsers";
	}
	// id passed is userPool id
	@RequestMapping(value = "/pool/users/matrix/{id}", method = RequestMethod.GET)
	public String getPoolUserMatrixView(@PathVariable Long id, Model model) {
		
		//gaeUserService
		
		List<GaeUser> users = new ArrayList<GaeUser>();
		UserPool userPool = userPoolService.getUserPool(id);
		Collection<UserPool> usersInPool = userPoolService
				.getAllUserPoolInfoForPool(userPool.getPoolId());
		for(UserPool userInPool : usersInPool){
			users.add(gaeUserService.findUser(userInPool.getUserId()));
			
		}
		
		List<MatchWithPredictions> matchesWithPreds = new ArrayList<MatchWithPredictions>();
		
		Collection<UserPrediction> userPreds = userPredService.getAllUserPredictionsForUserPool(id);
		Collection<Match> matches = matchService.getAllMatchesForEvent(userPool.getEventId());
		for(Match match : matches){
			if(!isHistory(match.getMatchDateTime())){
				continue;
			}
			MatchWithPredictions matchWithPred = new MatchWithPredictions(match.getMatchNo(), match.getSummary(), match.getMatchOutcome());
			Collection<UserPrediction> preds = userPredService.getAllUserPredictionsForMatrix(match.getId());
			for(UserPrediction predi:preds){
				for(UserPool userInPool : usersInPool){
					if(userInPool.getId().intValue()==predi.getUserPoolId().intValue()){
						matchWithPred.addUserPrediction(predi);
					}
					
				}
			}
			//matchWithPred.setUserPredictions();
			/*for(UserPrediction userPred:userPreds){
				if(userPred.getMatchNo().intValue()==(match.getMatchNo().intValue())){
					matchWithPred.addUserPrediction(userPred);
				}
			}*/
			matchesWithPreds.add(matchWithPred);
		}
		
		model.addAttribute("usersInPool", users);
		model.addAttribute("matchesWithPreds", matchesWithPreds);
		model.addAttribute("userPoolId",id);
		return "/pool/poolUsersMatrix";
	}
	
	private boolean isHistory(
			Date matchDateTimeAsCalendar) {
		//return  currentDateTime.after(matchDateTimeAsCalendar);
		Calendar matchDate = Calendar.getInstance();
		matchDate.setTime(matchDateTimeAsCalendar);
		Calendar current = Calendar.getInstance();
		matchDate.add(Calendar.MINUTE, -30);
		return  current.after(matchDate);
	}
	
	
}
